// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build ignore
// +build ignore

package main

import (
	"bytes"
	"fmt"
	"go/format"
	"log"
	"os"
	"runtime/metrics"
	"strconv"
	"strings"
	"text/template"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/internal"
)

func main() {
	if len(os.Args) != 2 {
		log.Fatal("requires Go version (e.g. go1.17) as an argument")
	}
	version, err := parseVersion(os.Args[1])
	if err != nil {
		log.Fatalf("parsing Go version: %v", err)
	}

	// Generate code.
	var buf bytes.Buffer
	err = testFile.Execute(&buf, struct {
		Descriptions []metrics.Description
		GoVersion    goVersion
	}{
		Descriptions: metrics.All(),
		GoVersion:    version,
	})
	if err != nil {
		log.Fatalf("executing template: %v", err)
	}

	// Format it.
	result, err := format.Source(buf.Bytes())
	if err != nil {
		log.Fatalf("formatting code: %v", err)
	}

	// Write it to a file.
	fname := fmt.Sprintf("go_collector_metrics_%s_test.go", version.Abbr())
	if err := os.WriteFile(fname, result, 0o644); err != nil {
		log.Fatalf("writing file: %v", err)
	}
}

type goVersion int

func (g goVersion) String() string {
	return fmt.Sprintf("go1.%d", g)
}

func (g goVersion) Abbr() string {
	return fmt.Sprintf("go1%d", g)
}

func parseVersion(s string) (goVersion, error) {
	i := strings.IndexRune(s, '.')
	if i < 0 {
		return goVersion(-1), fmt.Errorf("bad Go version format")
	}
	i, err := strconv.Atoi(s[i+1:])
	return goVersion(i), err
}

var testFile = template.Must(template.New("testFile").Funcs(map[string]interface{}{
	"rm2prom": func(d metrics.Description) string {
		ns, ss, n, ok := internal.RuntimeMetricsToProm(&d)
		if !ok {
			return ""
		}
		return prometheus.BuildFQName(ns, ss, n)
	},
	"nextVersion": func(version goVersion) string {
		return (version + goVersion(1)).String()
	},
}).Parse(`// Code generated by gen_go_collector_metrics_set.go; DO NOT EDIT.
//go:generate go run gen_go_collector_metrics_set.go {{.GoVersion}}

//go:build {{.GoVersion}} && !{{nextVersion .GoVersion}}
// +build {{.GoVersion}},!{{nextVersion .GoVersion}}

package prometheus

var expectedRuntimeMetrics = map[string]string{
{{- range .Descriptions -}}
	{{- $trans := rm2prom . -}}
	{{- if ne $trans "" }}
	{{.Name | printf "%q"}}: {{$trans | printf "%q"}},
	{{- end -}}
{{end}}
}
`))
